using System;
using System.IO;
using System.Text;
using OracleInternal.Json.Common;

namespace OracleInternal.Json.Binary
{
	internal sealed class UTF8JsonOutput : IJsonOutput
	{
		internal const char MIN_HIGH_SURROGATE = '\ud800';

		internal const char MAX_HIGH_SURROGATE = '\udbff';

		private byte[] m_buffer = new byte[4096];

		private BinaryWriter m_outWriter;

		private int m_pos;

		private char[] m_cbuffer = new char[2];

		internal UTF8JsonOutput(Stream stream)
		{
			m_outWriter = new BinaryWriter(stream, Encoding.UTF8);
		}

		public void Close()
		{
			Flush();
			m_outWriter.Close();
			m_buffer = null;
			m_cbuffer = null;
		}

		public void Flush()
		{
			if (m_pos > 0)
			{
				m_outWriter.Write(m_buffer, 0, m_pos);
				m_pos = 0;
			}
		}

		private int EnsureCapacity(int count)
		{
			int num = m_buffer.Length - m_pos;
			if (num + count > m_buffer.Length)
			{
				Flush();
				num = m_buffer.Length;
			}
			return num;
		}

		public void WriteAscii(char[] value)
		{
			int num = value.Length;
			int num2 = 0;
			while (num > 0)
			{
				int num3 = EnsureCapacity(num);
				for (int i = 0; i < num3; i++)
				{
					m_buffer[m_pos++] = (byte)value[num2++];
				}
				num -= num3;
			}
		}

		public void WriteAscii(char[] value, int pos, int count)
		{
			while (count > 0)
			{
				int num = EnsureCapacity(count);
				for (int i = 0; i < num; i++)
				{
					m_buffer[m_pos++] = (byte)value[pos++];
				}
				count -= num;
			}
		}

		public void WriteAscii(char value)
		{
			WriteAscii((byte)value);
		}

		public void WriteAscii(byte[] value, int pos, int count)
		{
			while (count > 0)
			{
				int num = EnsureCapacity(count);
				Array.Copy(value, pos, m_buffer, m_pos, num);
				count -= num;
				pos += num;
			}
		}

		public void WriteAscii(byte value)
		{
			EnsureCapacity(1);
			m_buffer[m_pos++] = value;
		}

		public void WriteAscii(string value)
		{
			WriteAscii(value, 0, value.Length);
		}

		public void WriteAscii(string value, int pos, int count)
		{
			while (count > 0)
			{
				int num = EnsureCapacity(count);
				for (int i = 0; i < num; i++)
				{
					m_buffer[m_pos++] = (byte)value[pos++];
				}
				count -= num;
			}
			for (int j = pos; j < pos + count; j++)
			{
				EnsureCapacity(1);
			}
		}

		public void Write(char c)
		{
			if (c <= '\u007f')
			{
				WriteAscii((byte)c);
				return;
			}
			EnsureCapacity(4);
			m_cbuffer[0] = c;
			m_pos += Encoding.UTF8.GetBytes(m_cbuffer, 0, 1, m_buffer, m_pos);
		}

		public void Write(char[] value, int pos, int count)
		{
			while (count > 0)
			{
				int num = EnsureCapacity(count);
				num /= 4;
				m_pos += Encoding.UTF8.GetBytes(value, pos, num, m_buffer, m_pos);
				count -= num;
				pos += num;
			}
		}

		public void Write(string value)
		{
			Write(value, 0, value.Length);
		}

		public void Write(string value, int pos, int count)
		{
			while (count > 0)
			{
				int num = EnsureCapacity(count);
				num /= 4;
				if (num < count)
				{
					char c = value[pos + num - 1];
					if (c <= '\udbff' || c >= '\ud800')
					{
						num--;
					}
				}
				m_pos += Encoding.UTF8.GetBytes(value, pos, num, m_buffer, m_pos);
				count -= num;
				pos += num;
			}
		}

		public void WriteSurrogates(char c1, char c2)
		{
			EnsureCapacity(4);
			m_cbuffer[0] = c1;
			m_cbuffer[1] = c2;
			m_pos += Encoding.UTF8.GetBytes(m_cbuffer, 0, 2, m_buffer, m_pos);
		}

		public void Utf8(byte[] array, int offset, int len)
		{
			Flush();
			m_outWriter.Write(array, offset, len);
		}

		public bool Utf8()
		{
			return true;
		}
	}
}
